/*
* Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
*/
#include "vpc_pipe_comm.h"
#include "dvpp_cmdlist_log.h"
#include "dvpp_cmdlist_define.h"

uint64_t get_cvdr_base_addr(const vpc_pipe_pic_info_t *pic, const vpc_fmt_info_t *fmt_info,
    uint32_t wstride[COLOR_CHNANNEL_NUM], uint32_t top, uint32_t left, uint32_t port)
{
    uint64_t top_offset;
    uint64_t left_offset;
    uint64_t chn0_offset;
    uint64_t chn1_offset;
    uint64_t chn2_offset;
    uint64_t y_step = vpc_pipe_get_pixel_step(fmt_info, Y);

    if (port == PORT0) {
        top_offset = (uint64_t)(wstride[PORT0]) * top;
        left_offset = vpc_pipe_get_offset(fmt_info, left, PORT0);
    } else if (port == PORT1) {
        chn0_offset = (uint64_t)(wstride[PORT0]) * pic->picture_height_stride;
        chn1_offset = (uint64_t)(wstride[PORT1]) * (top / y_step);
        top_offset = chn0_offset + chn1_offset;
        left_offset = vpc_pipe_get_offset(fmt_info, left, PORT1);
    } else {
        chn0_offset = (uint64_t)(wstride[PORT0]) * pic->picture_height_stride;
        chn1_offset = (uint64_t)(wstride[PORT1]) * (pic->picture_height_stride / y_step);
        chn2_offset = (uint64_t)(wstride[PORT2]) * (top / y_step);
        top_offset =  chn0_offset + chn1_offset + chn2_offset;
        left_offset = vpc_pipe_get_offset(fmt_info, left, PORT2);
    }

    return (uint64_t)(pic->picture_address) + top_offset + left_offset;
}

static void vpc_pipe_set_input_cvdr_port(
    const vpc_pipe_ctx_t *ctx, uint32_t wstride[COLOR_CHNANNEL_NUM], uint32_t port)
{
    uint32_t du = vpc_pipe_get_du_val(&SRC_FMTCFG_(ctx), port);
    uint32_t line_size = vpc_pipe_get_line_size(&SRC_FMTCFG_(ctx), SRCROI_(ctx).width, port);
    uint32_t frame_height = vpc_pipe_get_frame_height(&SRC_FMTCFG_(ctx), SRCROI_(ctx).height, port);
    uint32_t stride = wstride[port];
    uint64_t addr = get_cvdr_base_addr(
        &SRCPIC_(ctx), &SRC_FMTCFG_(ctx), wstride, SRCROI_(ctx).vmin, SRCROI_(ctx).hmin, port);

    if ((PIPELINE_(ctx).kernel.flip.enY != 0) && (PIPELINE_(ctx).kernel.flip.isPreY != 0)) {
        CHANNEL_(ctx).cvdr.vp.rd[port].yflipEn = 1;
        addr = get_cvdr_base_addr(
            &SRCPIC_(ctx), &SRC_FMTCFG_(ctx), wstride, SRCPIC_(ctx).picture_height - 1, SRCROI_(ctx).hmin, port);
    }

    CHANNEL_(ctx).cvdr.vp.rd[port].du = du;
    CHANNEL_(ctx).cvdr.vp.rd[port].lineSize = line_size - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].frameSize = frame_height - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].stride = stride - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].addr = addr;
}

void vpc_pipe_set_in0_cvdr_channel(const vpc_pipe_ctx_t *ctx)
{
    uint32_t wstride[COLOR_CHNANNEL_NUM] = {0};

    wstride[PORT0] = vpc_pipe_get_stride(&SRC_FMTCFG_(ctx), SRCPIC_(ctx).picture_width_stride, PORT0);
    wstride[PORT1] = vpc_pipe_get_stride(&SRC_FMTCFG_(ctx), SRCPIC_(ctx).picture_width_stride, PORT1);
    wstride[PORT2] = vpc_pipe_get_stride(&SRC_FMTCFG_(ctx), SRCPIC_(ctx).picture_width_stride, PORT2);

    CHANNEL_(ctx).cvdr.vp.rd[PORT0].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT0);
    CHANNEL_(ctx).cvdr.vp.rd[PORT1].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT1);
    CHANNEL_(ctx).cvdr.vp.rd[PORT2].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT2);

    vpc_pipe_set_input_cvdr_port(ctx, wstride, PORT0);

    if (vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT1) != IDEL) {
        vpc_pipe_set_input_cvdr_port(ctx, wstride, PORT1);
    }

    if (vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT2) != IDEL) {
        vpc_pipe_set_input_cvdr_port(ctx, wstride, PORT2);
    }

    // swap功能无法交换port0和port2的数据，需要软件交换二者地址
    if (vpc_pipe_get_fmt_rank(&SRC_FMTCFG_(ctx)) == BGR_PLANAR) {
        struct VP_RD tmp_rd = CHANNEL_(ctx).cvdr.vp.rd[PORT0];
        CHANNEL_(ctx).cvdr.vp.rd[PORT0] = CHANNEL_(ctx).cvdr.vp.rd[PORT2];
        CHANNEL_(ctx).cvdr.vp.rd[PORT2] = tmp_rd;
    }
}

static void vpc_pipe_set_input_cvdr_port_by_apart_info(
    const vpc_pipe_ctx_t *ctx, uint32_t port)
{
    uint32_t du = vpc_pipe_get_du_val(&SRC_FMTCFG_(ctx), port);
    uint32_t line_size = vpc_pipe_get_line_size(&SRC_FMTCFG_(ctx), SRC_APARTPIC_(ctx).width, port);
    uint32_t frame_height = vpc_pipe_get_frame_height(&SRC_FMTCFG_(ctx), SRC_APARTPIC_(ctx).height, port);
    uint64_t addr = SRC_APARTPIC_(ctx).addr[port];
    uint32_t stride = SRC_APARTPIC_(ctx).stride[port];

    CHANNEL_(ctx).cvdr.vp.rd[port].du = du;
    CHANNEL_(ctx).cvdr.vp.rd[port].lineSize = line_size - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].frameSize = frame_height - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].stride = stride - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].addr = addr;
}

void vpc_pipe_set_in0_cvdr_channel_by_apart_info(const vpc_pipe_ctx_t *ctx)
{
    CHANNEL_(ctx).cvdr.vp.rd[PORT0].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT0);
    CHANNEL_(ctx).cvdr.vp.rd[PORT1].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT1);
    CHANNEL_(ctx).cvdr.vp.rd[PORT2].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT2);

    vpc_pipe_set_input_cvdr_port_by_apart_info(ctx, PORT0);

    if (vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT1) != IDEL) {
        vpc_pipe_set_input_cvdr_port_by_apart_info(ctx, PORT1);
    }

    if (vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT2) != IDEL) {
        vpc_pipe_set_input_cvdr_port_by_apart_info(ctx, PORT2);
    }
}

static void vpc_pipe_set_output_cvdr_port(
    const vpc_pipe_ctx_t *ctx, uint32_t top_off, uint32_t left_off, uint32_t paste_width,
    uint32_t wstride[COLOR_CHNANNEL_NUM], uint32_t chn, uint32_t port)
{
    uint32_t port_idx = port + chn * PORT_STEP;
    uint32_t line_size = vpc_pipe_get_line_size(&DST_FMTCFG_(ctx, chn), paste_width, port);
    uint64_t addr = get_cvdr_base_addr(
        &DSTPIC_(ctx, chn), &DST_FMTCFG_(ctx, chn), wstride, top_off, left_off, port);
    uint32_t stride = wstride[port];

    if ((PIPELINE_(ctx).kernel.flip.enY != 0) && (PIPELINE_(ctx).kernel.flip.isPreY == 0)) {
        CHANNEL_(ctx).cvdr.vp.wr[port].yflipEn = 1;
        addr = get_cvdr_base_addr(
            &DSTPIC_(ctx, chn), &DST_FMTCFG_(ctx, chn), wstride, DSTPIC_(ctx, chn).picture_height - 1, left_off, port);
    }

    CHANNEL_(ctx).cvdr.vp.wr[port_idx].lineSize = line_size - 1;
    CHANNEL_(ctx).cvdr.vp.wr[port_idx].stride = stride - 1;
    CHANNEL_(ctx).cvdr.vp.wr[port_idx].addr = addr;
}

void vpc_pipe_set_paste(const vpc_pipe_ctx_t *ctx, uint32_t top_off, uint32_t left_off, uint32_t width, uint32_t chn)
{
    uint32_t wstride[COLOR_CHNANNEL_NUM] = {0};

    wstride[PORT0] = vpc_pipe_get_stride(&DST_FMTCFG_(ctx, chn), DSTPIC_(ctx, chn).picture_width_stride, PORT0);
    wstride[PORT1] = vpc_pipe_get_stride(&DST_FMTCFG_(ctx, chn), DSTPIC_(ctx, chn).picture_width_stride, PORT1);
    wstride[PORT2] = vpc_pipe_get_stride(&DST_FMTCFG_(ctx, chn), DSTPIC_(ctx, chn).picture_width_stride, PORT2);

    CHANNEL_(ctx).cvdr.vp.wr[PORT0 + chn * PORT_STEP].pixelFmt = vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT0);
    CHANNEL_(ctx).cvdr.vp.wr[PORT1 + chn * PORT_STEP].pixelFmt = vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT1);
    CHANNEL_(ctx).cvdr.vp.wr[PORT2 + chn * PORT_STEP].pixelFmt = vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT2);

    vpc_pipe_set_output_cvdr_port(ctx, top_off, left_off, width, wstride, chn, PORT0);
    if (vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT1) != IDEL) {
        vpc_pipe_set_output_cvdr_port(ctx, top_off, left_off, width, wstride, chn, PORT1);
    }

    if (vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT2) != IDEL) {
        vpc_pipe_set_output_cvdr_port(ctx, top_off, left_off, width, wstride, chn, PORT2);
    }

    // swap功能无法交换port0和port2的数据，需要软件交换二者地址
    if (vpc_pipe_get_fmt_rank(&DST_FMTCFG_(ctx, chn)) == BGR_PLANAR) {
        struct VP_WR tmp_wr = CHANNEL_(ctx).cvdr.vp.wr[PORT0 + chn * PORT_STEP];
        CHANNEL_(ctx).cvdr.vp.wr[PORT0 + chn * PORT_STEP] = CHANNEL_(ctx).cvdr.vp.wr[PORT2 + chn * PORT_STEP];
        CHANNEL_(ctx).cvdr.vp.wr[PORT2 + chn * PORT_STEP] = tmp_wr;
    }
}

void vpc_pipe_set_out_cvdr_channel(const vpc_pipe_ctx_t *ctx, uint32_t chn)
{
    vpc_pipe_set_paste(ctx, 0, 0, DSTPIC_(ctx, chn).picture_width, chn);
}

static void vpc_pipe_set_output_cvdr_port_by_apart_info(const vpc_pipe_ctx_t *ctx, uint32_t chn, uint32_t port)
{
    uint32_t port_idx = port + chn * PORT_STEP;
    uint32_t line_size = vpc_pipe_get_line_size(&DST_FMTCFG_(ctx, chn), DST_APARTPIC_(ctx, chn).width, port);
    uint64_t addr = DST_APARTPIC_(ctx, chn).addr[port]; // 当前不支持paste
    uint32_t stride = DST_APARTPIC_(ctx, chn).stride[port];

    CHANNEL_(ctx).cvdr.vp.wr[port_idx].lineSize = line_size - 1;
    CHANNEL_(ctx).cvdr.vp.wr[port_idx].stride = stride - 1;
    CHANNEL_(ctx).cvdr.vp.wr[port_idx].addr = addr;
}

void vpc_pipe_set_out_cvdr_channel_by_apart_info(const vpc_pipe_ctx_t *ctx, uint32_t chn)
{
    uint32_t wstride[COLOR_CHNANNEL_NUM] = {0};
    CHANNEL_(ctx).cvdr.vp.wr[PORT0 + chn * PORT_STEP].pixelFmt = vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT0);
    CHANNEL_(ctx).cvdr.vp.wr[PORT1 + chn * PORT_STEP].pixelFmt = vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT1);
    CHANNEL_(ctx).cvdr.vp.wr[PORT2 + chn * PORT_STEP].pixelFmt = vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT2);

    vpc_pipe_set_output_cvdr_port_by_apart_info(ctx, chn, PORT0);
    if (vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT1) != IDEL) {
        vpc_pipe_set_output_cvdr_port_by_apart_info(ctx, chn, PORT1);
    }

    if (vpc_pipe_get_pixel_fmt(&DST_FMTCFG_(ctx, chn), PORT2) != IDEL) {
        vpc_pipe_set_output_cvdr_port_by_apart_info(ctx, chn, PORT2);
    }
}

void vpc_pipe_set_cvdr_rd_nr(const vpc_pipe_ctx_t *ctx, uint8_t port, uint8_t du)
{
    CHANNEL_(ctx).cvdr.nr.rd[port].allocatedDu = du;
}

static void vpc_pipe_in0_cvdr_copy_1port_to_3port(
    const vpc_pipe_ctx_t *ctx, uint32_t wstride[COLOR_CHNANNEL_NUM], uint32_t port)
{
    uint32_t du = vpc_pipe_get_du_val(&SRC_FMTCFG_(ctx), PORT0);
    uint32_t line_size = vpc_pipe_get_line_size(&SRC_FMTCFG_(ctx), SRCROI_(ctx).width, PORT0);
    uint32_t frame_height = vpc_pipe_get_frame_height(&SRC_FMTCFG_(ctx), SRCROI_(ctx).height, PORT0);
    uint64_t addr = get_cvdr_base_addr(
        &SRCPIC_(ctx), &SRC_FMTCFG_(ctx), wstride, SRCROI_(ctx).vmin, SRCROI_(ctx).hmin, PORT0);
    uint32_t stride = vpc_pipe_get_stride(&SRC_FMTCFG_(ctx), SRCPIC_(ctx).picture_width_stride, PORT0);

    CHANNEL_(ctx).cvdr.vp.rd[port].du = du;
    CHANNEL_(ctx).cvdr.vp.rd[port].lineSize = line_size - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].frameSize = frame_height - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].stride = stride - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].addr = addr;
}

void vpc_pipe_in0_cvdr_copy_1chn_to_3chn(const vpc_pipe_ctx_t *ctx)
{
    uint32_t i;
    uint32_t wstride[COLOR_CHNANNEL_NUM] = {0};

    wstride[PORT0] = vpc_pipe_get_stride(&SRC_FMTCFG_(ctx), SRCPIC_(ctx).picture_width_stride, PORT0);
    wstride[PORT1] = wstride[PORT0];
    wstride[PORT2] = wstride[PORT0];

    CHANNEL_(ctx).cvdr.vp.rd[PORT0].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT0);
    CHANNEL_(ctx).cvdr.vp.rd[PORT1].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT1);
    CHANNEL_(ctx).cvdr.vp.rd[PORT2].pixelFmt = vpc_pipe_get_pixel_fmt(&SRC_FMTCFG_(ctx), PORT2);

    for (i = 0; i < COLOR_CHNANNEL_NUM; i++) {
        if (CHANNEL_(ctx).cvdr.vp.rd[i].pixelFmt != IDEL) {
            vpc_pipe_in0_cvdr_copy_1port_to_3port(ctx, wstride, i);
        }
    }
}

void vpc_pipe_set_input_cvdr_port_for_single_chn_by_pic(
    const vpc_pipe_ctx_t *ctx, const vpc_pipe_pic_info_t *pic, uint32_t port)
{
    vpc_fmt_info_t fmt_info;
    vpc_pipe_init_format_info(&fmt_info, pic->picture_format);

    CHANNEL_(ctx).cvdr.vp.rd[port].pixelFmt = vpc_pipe_get_pixel_fmt(&fmt_info, PORT0);
    CHANNEL_(ctx).cvdr.vp.rd[port].du = vpc_pipe_get_du_val(&fmt_info, PORT0);
    CHANNEL_(ctx).cvdr.vp.rd[port].lineSize = vpc_pipe_get_line_size(&fmt_info, pic->picture_width, PORT0) - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].frameSize = vpc_pipe_get_frame_height(&fmt_info, pic->picture_height, PORT0) - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].stride = vpc_pipe_get_stride(&fmt_info, pic->picture_width_stride, PORT0) - 1;
    CHANNEL_(ctx).cvdr.vp.rd[port].addr = (uint64_t)(pic->picture_address);
}

void vpc_pipe_set_output_cvdr_idle(const vpc_pipe_ctx_t *ctx)
{
    CHANNEL_(ctx).cvdr.vp.wr[PORT0].pixelFmt = IDEL;
    CHANNEL_(ctx).cvdr.vp.wr[PORT1].pixelFmt = IDEL;
    CHANNEL_(ctx).cvdr.vp.wr[PORT2].pixelFmt = IDEL;
}

void vpc_pipe_set_rdma_channel(const vpc_pipe_ctx_t *ctx)
{
    TOP_(ctx).rdChannelSel = RDMA_CHANNEL;
    CHANNEL_(ctx).rdma.srcyhAddrL = GET_LOW_ADDR(SRCHFBC_(ctx).luma_head_addr);
    CHANNEL_(ctx).rdma.srcyhAddrH = GET_HIGH_ADDR(SRCHFBC_(ctx).luma_head_addr);
    CHANNEL_(ctx).rdma.srcchAddrL = GET_LOW_ADDR(SRCHFBC_(ctx).chroma_head_addr);
    CHANNEL_(ctx).rdma.srcchAddrH = GET_HIGH_ADDR(SRCHFBC_(ctx).chroma_head_addr);
    CHANNEL_(ctx).rdma.srcyhStride = SRCHFBC_(ctx).luma_head_stride;
    CHANNEL_(ctx).rdma.srcchStride = SRCHFBC_(ctx).chroma_head_stride;
    CHANNEL_(ctx).rdma.srcyAddrL = GET_LOW_ADDR(SRCHFBC_(ctx).luma_payload_addr);
    CHANNEL_(ctx).rdma.srcyAddrH = GET_HIGH_ADDR(SRCHFBC_(ctx).luma_payload_addr);
    CHANNEL_(ctx).rdma.srccAddrL = GET_LOW_ADDR(SRCHFBC_(ctx).chroma_payload_addr);
    CHANNEL_(ctx).rdma.srccAddrH = GET_HIGH_ADDR(SRCHFBC_(ctx).chroma_payload_addr);
    CHANNEL_(ctx).rdma.srcyStride = SRCHFBC_(ctx).luma_payload_stride;
    CHANNEL_(ctx).rdma.srccStride = SRCHFBC_(ctx).chroma_payload_stride;
}